package org.zoeframework.core;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.zoeframework.aop.annotation.Aspect;
import org.zoeframework.core.annotation.Component;
import org.zoeframework.core.annotation.Controller;
import org.zoeframework.core.annotation.Repository;
import org.zoeframework.core.annotation.Service;
import org.zoeframework.util.ClassUtil;

import java.lang.annotation.Annotation;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author Zoe.Zhang
 * @date 2022/01/19
 * @description
 */
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class BeanContainer {
    /**
     * 存放所有被标记的类,以Class和Object的方式存储
     */
    private static final Map<Class<?>, Object> beanMap = MapUtil.newConcurrentHashMap();

    /**
     * 会被扫描加载到容器注解列表
     */
    private static final List<Class<? extends Annotation>> BEAN_ANNOTATIONS = CollUtil.toList(Controller.class, Service.class, Repository.class, Component.class, Aspect.class);

    /**
     * 判断容器是否被加载过
     */
    private boolean loaded;

    public boolean isLoaded() {
        return loaded;
    }

    /**
     * 单例Bean容器实现
     *
     * @return
     */
    public static BeanContainer getInstance() {
        return BeanContainerHolder.HOLDER.instance;
    }

    private enum BeanContainerHolder {
        HOLDER;
        private BeanContainer instance;

        BeanContainerHolder() {
            instance = new BeanContainer();
        }
    }

    /**
     * 获取beanMap中Bean的数量
     *
     * @return
     */
    public int getBeanSize() {
        return beanMap.size();
    }

    /**
     * 加载所有Beans并添加到BeanMap中
     *
     * @param packageName 包名
     */
    public synchronized void loadBeans(String packageName) {
        if (isLoaded()) {
            log.error("beanContainer has been isLoaded");
            return;
        }
        // 获取指定包名下面所有的Clazz
        Set<Class<?>> clazzSet = ClassUtil.extractPackageClass(packageName);
        if (CollUtil.isEmpty(clazzSet)) {
            log.error("classSet 为空===>{}", packageName);
            return;
        }
        for (Class<?> beanClazz : clazzSet) {
            for (Class<? extends Annotation> beanAnnotation : BEAN_ANNOTATIONS) {
                // 如果clazz被容器注解所修饰,就往容器里面添加
                if (AnnotationUtil.hasAnnotation(beanClazz, beanAnnotation)) {
                    beanMap.put(beanClazz, ClassUtil.newInstance(beanClazz, true));
                }
            }
        }
        // 表示容器已经被加载过了
        loaded = true;
    }

    /**
     * 添加一个Clazz对象以及对应的Bean实例
     *
     * @param clazz class对象
     * @param bean  bean实例
     * @return 原有的bean实例
     */
    public Object addBean(Class<?> clazz, Object bean) {
        return beanMap.put(clazz, bean);
    }

    /**
     * 根据clazz删除对应的Bean
     *
     * @param clazz class对象
     * @return 被删除的bean实例
     */
    public Object removeBean(Class<?> clazz) {
        return beanMap.remove(clazz);
    }

    /**
     * 根据Clazz对象获取对应的bean实例
     *
     * @param clazz class对象
     * @return bean实例
     */
    public Object getBean(Class<?> clazz) {
        return beanMap.get(clazz);
    }

    /**
     * 获取beanMap中所有的key
     *
     * @return class集合
     */
    public Set<Class<?>> getClasses() {
        return beanMap.keySet();
    }

    /**
     * 获取所有beanMap中的value集合
     *
     * @return bean集合
     */
    public Set<Object> getBeans() {
        return CollUtil.newHashSet(beanMap.values());
    }

    /**
     * 根据注解获取所有的class对象
     *
     * @param annotation 注解
     * @return 结果集
     */
    public Set<Class<?>> getClassesByAnnotation(Class<? extends Annotation> annotation) {
        Set<Class<?>> keySet = getClasses();
        if (CollUtil.isEmpty(keySet)) {
            log.warn("nothing in beanMap");
            return null;
        }
        keySet = keySet.stream()
                       .filter(clazz -> AnnotationUtil.hasAnnotation(clazz, annotation))
                       .collect(Collectors.toSet());
        return CollUtil.isNotEmpty(keySet) ? keySet : null;
    }

    /**
     * 通过接口或者父类获取实现类或者子类的class集合,不包括其本身
     *
     * @param interfaceOrClass
     * @return
     */
    public Set<Class<?>> getClassesBySuper(Class<?> interfaceOrClass) {
        Set<Class<?>> clazzSet = getClasses();
        if (CollUtil.isEmpty(clazzSet)) {
            log.warn("nothing in beanMap");
            return null;
        }
        clazzSet = clazzSet.stream()
                           .filter(clazz -> interfaceOrClass.isAssignableFrom(clazz) && ObjectUtil.notEqual(interfaceOrClass, clazz))
                           .collect(Collectors.toSet());
        return CollUtil.isNotEmpty(clazzSet) ? clazzSet : null;
    }
}
